﻿using System;
using System.Collections.Generic;
using System.Linq;
#if NETFX_CORE
using System.Reflection;
using Windows.UI.Xaml.Navigation;
#else
using System.Windows.Navigation;
#endif
using MugenMvvmToolkit.Infrastructure;

using MugenMvvmToolkit.Interfaces;

using MugenMvvmToolkit.Models;


namespace MugenMvvmToolkit.Utils
{
#if WPF
    internal static partial class MvvmUtilsInternalAdvanced
#else
    internal static partial class MvvmUtilsInternal
#endif

    {
        #region Fields

        internal static readonly Dictionary<string, string> EmptyUriDictionary = new Dictionary<string, string>();

        #endregion

        #region Methods
#if !NETFX_CORE
        internal static IDictionary<string, string> GetUriParameters(this UriParameter[] uriParameters)
        {
            if (uriParameters == null || uriParameters.Length == 0)
                return EmptyUriDictionary;
            return uriParameters.ToDictionary(pair => pair.Key, pair => pair.Value);
        }

        internal static IViewPageMappingItem MergeUri(this IViewPageMappingItem viewPageMappingItem,
                                                              IDictionary<string, string> uriParameters)
        {
            Should.NotBeNull(viewPageMappingItem, "viewPageMappingItem");
            return new ViewPageMappingItem(BuildQueryString(viewPageMappingItem.Uri, uriParameters),
                viewPageMappingItem.ViewModelType, viewPageMappingItem.ViewType, viewPageMappingItem.Name);
        }

        internal static Uri MergeUri(this Uri uri, IDictionary<string, string> uriParameters)
        {
            if (uriParameters == null)
                return uri;
            Should.NotBeNull(uri, "uri");
            return BuildQueryString(uri, uriParameters);
        }

        internal static IDictionary<string, string> GetUriParameters(this NavigatingCancelEventArgs args)
        {
            Should.NotBeNull(args, "args");
            var uri = args.Uri;
            return InternalUriParseQueryStringToDictionary(uri);
        }

        internal static IDictionary<string, string> GetUriParameters(this NavigationEventArgs args)
        {
            Should.NotBeNull(args, "args");
            var uri = args.Uri;
            return InternalUriParseQueryStringToDictionary(uri);
        }

        internal static IDictionary<string, string> InternalUriParseQueryStringToDictionary(Uri uri)
        {
            if (uri == null)
                return EmptyUriDictionary;
            var dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
            foreach (
                string url in
                    MakeAbsolute(uri)
                        .GetComponents(UriComponents.Query, UriFormat.SafeUnescaped)
                        .Split("&".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
            {
                int length = url.IndexOf("=", StringComparison.Ordinal);
                if (length == -1)
                    dictionary.Add(UrlDecode(url), string.Empty);
                else
                    dictionary.Add(UrlDecode(url.Substring(0, length)), UrlDecode(url.Substring(length + 1)));
            }
            return dictionary;
        }

        internal static Uri BuildQueryString(Uri uri, IDictionary<string, string> queryString)
        {
            if (queryString.Count < 1)
                return uri;

            IDictionary<string, string> dictionary = InternalUriParseQueryStringToDictionary(uri);
            if (dictionary.Count == 0)
                dictionary = new Dictionary<string, string>();
            foreach (var param in queryString)
                dictionary[param.Key] = param.Value;

            string result = dictionary
                .Aggregate("?", (current, pair) => current + (pair.Key + "=" + Uri.EscapeDataString(pair.Value) + "&"));
            result = result.Remove(result.Length - 1);
            if (uri.IsAbsoluteUri)
                return new Uri(uri.OriginalString.Replace(uri.Query, result));
            int indexOf = uri.OriginalString.IndexOf('?');
            if (indexOf == -1)
                indexOf = uri.OriginalString.Length;
            return new Uri(uri.OriginalString.Substring(0, indexOf) + result, UriKind.Relative);
        }

        private static string UrlDecode(string value)
        {
#if SILVERLIGHT && !WINDOWS_PHONE
            return System.Windows.Browser.HttpUtility.UrlDecode(value);
#else
            return Uri.UnescapeDataString(value);
#endif
        }

        private static Uri MakeAbsolute(Uri baseUri)
        {
            if (baseUri == null || baseUri.OriginalString.StartsWith("/", StringComparison.Ordinal))
                return new Uri("http://localhost" + baseUri, UriKind.Absolute);
            return new Uri("http://localhost/" + baseUri, UriKind.Absolute);
        }
#else
        internal static PropertyInfo GetProperty(this Type type, string propertyName)
        {
            return type.GetTypeInfo().GetDeclaredProperty(propertyName);
        }

#endif

        #endregion
    }
}